﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Authorize.Core.Entity;
using Authorize.Core.Enums;
using Authorize.Core.Repository.Implement;
using Authorize.Core.Store;
using IdentityServer4.Models;

namespace Authorize.Core.Cache
{
    public static class ConstDataCache
    {
        public static List<Client> ClientSourceCache { get; }

        public static List<ApiResource> ApiResourcesCache { get; }

        static ConstDataCache()
        {
            ClientSourceCache = new List<Client>();
            var repository = new ClientSourceRepository();
            var entities = repository.GetAll();
            ClientSourceCache = entities.Select(ConvertToClient).ToList();

            var apiRepository = new ApiSourceRepository();
            var apiEntities = apiRepository.GetAll();
            ApiResourcesCache = apiEntities.Select(ConvertToApiResource).ToList();
        }

        public static void AddClient(Client client)
        {
            var oldClient = ClientSourceCache.Find(x => x.ClientId == client.ClientId);
            if (oldClient != null)
            {
                ClientSourceCache.Remove(oldClient);
            }

            if (client != null)
            {
                ClientSourceCache.Add(client);
            }
        }

        public static void AddClient(ClientSourceEntity entity)
        {
            var client = ConvertToClient(entity);
            AddClient(client);
        }

        public static void UpdateClient(Client client)
        {
            AddClient(client);
        }

        public static void RemoveClient(string clientId)
        {
            var client = ClientSourceCache.Find(x => x.ClientId == clientId);
            ClientSourceCache.Remove(client);
        }

        public static void UpdateApiResource(ApiSourceEntity entity)
        {
            var oldApiResource = ApiResourcesCache.Find(x => x.Name == entity.ApiCode);
            if (oldApiResource != null)
            {
                ApiResourcesCache.Remove(oldApiResource);
            }

            ApiResourcesCache.Add(ConvertToApiResource(entity));
        }

        public static void Remove(string apiCode)
        {
            var oldApiResource = ApiResourcesCache.Find(x => x.Name == apiCode);
            ApiResourcesCache.Remove(oldApiResource);
        }

        private static Client ConvertToClient(ClientSourceEntity entity)
        {
            var client = new Client();
            switch (entity.Type)
            {
                case ClientType.BackEnd:
                    client.ClientId = entity.ClientId;
                    client.ClientName = entity.ClientName;
                    client.AllowedGrantTypes = GrantTypes.HybridAndClientCredentials;
                    client.ClientSecrets = new List<Secret> { new Secret(entity.ClientSecrets) };

                    client.RedirectUris = entity.RedirectUris.Split(",");
                    client.PostLogoutRedirectUris = entity.PostLogoutRedirectUris.Split(",");
                    client.AllowedScopes = entity.AllowedScopes.Split(",");
                    client.AllowOfflineAccess = true;

                    break;
                case ClientType.FrondEnd:
                    client.ClientId = entity.ClientId;
                    client.ClientName = entity.ClientName;
                    client.AllowedGrantTypes = GrantTypes.Implicit;
                    client.AllowAccessTokensViaBrowser = true;
                    client.RequireConsent = false;

                    client.RedirectUris = entity.RedirectUris.Split(",");
                    client.PostLogoutRedirectUris = entity.PostLogoutRedirectUris.Split(",");
                    client.AllowedCorsOrigins = entity.AllowedCorsOrigins.Split(",");

                    client.AlwaysSendClientClaims = true;
                    client.AlwaysIncludeUserClaimsInIdToken = true;
                    client.AlwaysIncludeUserClaimsInIdToken = true;

                    client.AllowedScopes = entity.AllowedScopes.Split(",");
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            return client;
        }

        private static ApiResource ConvertToApiResource(ApiSourceEntity entity)
        {
            return new ApiResource(entity.ApiCode, entity.ApiName);
        }
    }
}
